/**
 * 工具函数集合 - 常见的数据转换和格式化工具
 * 通用库
 */

import fs from 'fs';
/**
 * 生成随机字符串
 * @param {number} len 随机字符串的长度，默认32,最小为6
 * @param {number} type 随机字符串的类型：0-纯字母，1-数字字母混搭，2-纯数字，3-特殊字符混搭
 * @returns {string} 返回随机的字符串
 *
 */
const stringRandom = (len = 32, type = 0) => {
	let chars = '';
	if (isNaN(len)) {
		len = 32;
	}
	if (len < 6) {
		len = 6;
	}
	if (isNaN(type)) {
		type = 0;
	}
	switch (type) {
		case 0: // 首字母+字母数字混搭（排除易混淆字符）
			chars = "ABCDEFGHJKMNPQRSTWXYZabcdefhijkmnprstwxyz";
			chars = stringRandom(1, 0) + stringRandom(len - 1, 1);
			break;
		case 1: // 数字字母混搭（排除易混淆字符）
			chars = "ABCDEFGHJKMNPQRSTWXYZabcdefhijkmnprstwxyz2345678";
			break;
		case 2: // 纯数字
			chars = "0123456789";
			break;
		case 3: // 特殊字符混搭
			chars = "ABCDEFGHJKMNPQRSTWXYZabcdefhijkmnprstwxyz2345678!@#$%^&*()_+-=";
			break;
		case 4: // 纯字母（排除易混淆字符）
			chars = "ABCDEFGHJKMNPQRSTWXYZabcdefhijkmnprstwxyz2345678!@#$%^&*()_+-=";
			break;
		default:
			chars = "ABCDEFGHJKMNPQRSTWXYZabcdefhijkmnprstwxyz";
			break;
	}

	let result = '';
	for (let i = 0; i < len; i++) {
		result += chars.charAt(Math.floor(Math.random() * chars.length));
	}
	return result;
}

/**
 * 时间格式化
 * @param {number|string|Date} timestamp 时间戳或日期对象
 * @param {string} format 格式化模板，默认 'YYYY-MM-DD HH:mm:ss'
 * @returns {string} 格式化后的时间字符串
 */
const timeFormat = (timestamp, format = 'YYYY-MM-DD HH:mm:ss') => {
	let date;

	// 处理不同类型的输入
	if (timestamp instanceof Date) {
		date = timestamp;
	} else if (typeof timestamp === 'string') {
		date = new Date(timestamp);
	} else if (typeof timestamp === 'number') {
		// 时间戳为10位需*1000，时间戳为13位的话不需乘1000
		date = new Date(timestamp < 10000000000 ? timestamp * 1000 : timestamp);
	} else {
		date = new Date();
	}

	// 检查日期是否有效
	if (isNaN(date.getTime())) {
		return 'Invalid Date';
	}

	const year = date.getFullYear();
	const month = date.getMonth() + 1;
	const day = date.getDate();
	const hours = date.getHours();
	const minutes = date.getMinutes();
	const seconds = date.getSeconds();

	// 补零函数
	const padZero = (num) => num < 10 ? '0' + num : num;

	// 替换格式化模板
	return format
		.replace(/YYYY/g, year)
		.replace(/YY/g, String(year).slice(-2))
		.replace(/MM/g, padZero(month))
		.replace(/M/g, month)
		.replace(/DD/g, padZero(day))
		.replace(/D/g, day)
		.replace(/HH/g, padZero(hours))
		.replace(/H/g, hours)
		.replace(/mm/g, padZero(minutes))
		.replace(/m/g, minutes)
		.replace(/ss/g, padZero(seconds))
		.replace(/s/g, seconds);
}

/**
 * 文件大小格式化
 * @param {number} bytes 字节数
 * @param {number} decimals 小数位数，默认2
 * @returns {string} 格式化后的文件大小
 */
const formatFileSize = (bytes, decimals = 2) => {
	if (bytes === 0) return '0 Bytes';

	const k = 1024;
	const dm = decimals < 0 ? 0 : decimals;
	const sizes = ['Bytes', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB'];

	const i = Math.floor(Math.log(bytes) / Math.log(k));

	return parseFloat((bytes / Math.pow(k, i)).toFixed(dm)) + ' ' + sizes[i];
}

/**
 * 数字格式化（千分位分隔符）
 * @param {number} num 数字
 * @param {number} decimals 小数位数，默认0
 * @returns {string} 格式化后的数字
 */
const formatNumber = (num, decimals = 0) => {
	if (isNaN(num)) return '0';

	const parts = parseFloat(num).toFixed(decimals).split('.');
	parts[0] = parts[0].replace(/\B(?=(\d{3})+(?!\d))/g, ',');

	return parts.join('.');
}

/**
 * 手机号格式化
 * @param {string} phone 手机号
 * @param {string} separator 分隔符，默认空格
 * @returns {string} 格式化后的手机号
 */
const formatPhone = (phone, separator = ' ') => {
	if (!phone) return '';

	// 移除非数字字符
	const cleanPhone = phone.replace(/\D/g, '');

	if (cleanPhone.length === 11) {
		return cleanPhone.replace(/(\d{3})(\d{4})(\d{4})/, `$1${separator}$2${separator}$3`);
	} else if (cleanPhone.length === 10) {
		return cleanPhone.replace(/(\d{3})(\d{3})(\d{4})/, `$1${separator}$2${separator}$3`);
	}

	return phone;
}

/**
 * 银行卡号格式化
 * @param {string} cardNumber 银行卡号
 * @param {string} separator 分隔符，默认空格
 * @returns {string} 格式化后的银行卡号
 */
const formatCardNumber = (cardNumber, separator = ' ') => {
	if (!cardNumber) return '';

	// 移除非数字字符
	const cleanCard = cardNumber.replace(/\D/g, '');

	// 每4位添加分隔符
	return cleanCard.replace(/(\d{4})(?=\d)/g, `$1${separator}`);
}

/**
 * 身份证号格式化
 * @param {string} idCard 身份证号
 * @returns {string} 格式化后的身份证号
 */
const formatIdCard = (idCard) => {
	if (!idCard) return '';

	// 移除非数字和X字符
	const cleanId = idCard.replace(/[^\dXx]/g, '');

	if (cleanId.length === 18) {
		return cleanId.replace(/(\d{6})(\d{4})(\d{4})(\w{4})/, '$1 $2 $3 $4');
	} else if (cleanId.length === 15) {
		return cleanId.replace(/(\d{6})(\d{2})(\d{2})(\d{3})/, '$1 $2 $3 $4');
	}

	return idCard;
}

/**
 * 金额格式化（人民币）
 * @param {number} amount 金额
 * @param {number} decimals 小数位数，默认2
 * @param {string} currency 货币符号，默认￥
 * @returns {string} 格式化后的金额
 */
const formatCurrency = (amount, decimals = 2, currency = '￥') => {
	if (isNaN(amount)) return currency + '0.00';

	const num = parseFloat(amount);
	const formatted = num.toFixed(decimals);
	const parts = formatted.split('.');

	// 添加千分位分隔符
	parts[0] = parts[0].replace(/\B(?=(\d{3})+(?!\d))/g, ',');

	return currency + parts.join('.');
}

/**
 * 百分比格式化
 * @param {number} value 数值
 * @param {number} decimals 小数位数，默认2
 * @returns {string} 格式化后的百分比
 */
const formatPercent = (value, decimals = 2) => {
	if (isNaN(value)) return '0%';

	const num = parseFloat(value);
	return num.toFixed(decimals) + '%';
}

/**
 * 颜色值转换
 * @param {string} color 颜色值
 * @param {string} format 目标格式：hex, rgb, hsl
 * @returns {string} 转换后的颜色值
 */
const convertColor = (color, format = 'hex') => {
	// 创建临时元素来解析颜色
	const temp = document.createElement('div');
	temp.style.color = color;
	document.body.appendChild(temp);

	const computedColor = window.getComputedStyle(temp).color;
	document.body.removeChild(temp);

	if (!computedColor || computedColor === 'rgba(0, 0, 0, 0)') {
		return color;
	}

	// 解析RGB值
	const rgbMatch = computedColor.match(/rgba?\((\d+),\s*(\d+),\s*(\d+)(?:,\s*([\d.]+))?\)/);
	if (!rgbMatch) return color;

	const r = parseInt(rgbMatch[1]);
	const g = parseInt(rgbMatch[2]);
	const b = parseInt(rgbMatch[3]);
	const a = rgbMatch[4] ? parseFloat(rgbMatch[4]) : 1;

	switch (format) {
		case 'hex':
			const toHex = (n) => n.toString(16).padStart(2, '0');
			return `#${toHex(r)}${toHex(g)}${toHex(b)}`;
		case 'rgb':
			return a === 1 ? `rgb(${r}, ${g}, ${b})` : `rgba(${r}, ${g}, ${b}, ${a})`;
		case 'hsl':
			// RGB转HSL的简化实现
			const max = Math.max(r, g, b);
			const min = Math.min(r, g, b);
			const l = (max + min) / 2;

			if (max === min) {
				return `hsl(0, 0%, ${Math.round(l * 100 / 255)}%)`;
			}

			const d = max - min;
			const s = l > 127.5 ? d / (2 * 255 - max - min) : d / (max + min);
			let h;

			if (max === r) h = (g - b) / d + (g < b ? 6 : 0);
			else if (max === g) h = (b - r) / d + 2;
			else h = (r - g) / d + 4;

			h = Math.round(h * 60);
			return `hsl(${h}, ${Math.round(s * 100)}%, ${Math.round(l * 100 / 255)}%)`;
		default:
			return color;
	}
}

/**
 * 字符串截断
 * @param {string} str 原字符串
 * @param {number} length 最大长度
 * @param {string} suffix 后缀，默认...
 * @returns {string} 截断后的字符串
 */
const truncateString = (str, length, suffix = '...') => {
	if (!str || str.length <= length) return str;
	return str.substring(0, length) + suffix;
}

/**
 * 驼峰命名转下划线
 * @param {string} str 驼峰命名字符串
 * @returns {string} 下划线命名
 */
const camelToSnake = (str) => {
	return str.replace(/[A-Z]/g, letter => `_${letter.toLowerCase()}`);
}

/**
 * 下划线转驼峰命名
 * @param {string} str 下划线命名字符串
 * @param {boolean} pascal 是否转换为帕斯卡命名，默认false
 * @returns {string} 驼峰命名
 */
const snakeToCamel = (str, pascal = false) => {
	const result = str.replace(/_([a-z])/g, (match, letter) => letter.toUpperCase());
	return pascal ? result.charAt(0).toUpperCase() + result.slice(1) : result;
}

/**
 * 首字母大写
 * @param {string} str 字符串
 * @returns {string} 首字母大写的字符串
 */
const capitalize = (str) => {
	if (!str) return '';
	return str.charAt(0).toUpperCase() + str.slice(1).toLowerCase();
}

/**
 * 单词首字母大写
 * @param {string} str 字符串
 * @returns {string} 每个单词首字母大写的字符串
 */
const titleCase = (str) => {
	if (!str) return '';
	return str.replace(/\w\S*/g, word => capitalize(word));
}

/**
 * 获取文件扩展名
 * @param {string} fileName 文件名
 * @returns {string} 文件扩展名
 */
const getFileExtension = (fileName) => {
	const lastDotIndex = fileName.lastIndexOf('.');
	return lastDotIndex > 0 ? fileName.substring(lastDotIndex).toLowerCase() : '';
}

/**
 * 生成日期字符串 (YYYYMMDD)
 * @returns {string} 日期字符串
 */
const getDateString = () => {
	const now = new Date();
	const year = now.getFullYear();
	const month = String(now.getMonth() + 1).padStart(2, '0');
	const day = String(now.getDate()).padStart(2, '0');
	return `${year}${month}${day}`;
}

/**
 * 根据文件名自动检测文件类型
 * @param {string} fileName 文件名
 * @returns {string} 文件类型
 */
const detectFileType = (fileName) => {
	const ext = getFileExtension(fileName).toLowerCase();

	// 图片类型
	const imageExtensions = ['.jpg', '.jpeg', '.png', '.gif', '.webp', '.bmp', '.tiff', '.svg'];
	if (imageExtensions.includes(ext)) {
		return 'image';
	}

	// 视频类型
	const videoExtensions = ['.mp4', '.avi', '.mov', '.wmv', '.flv', '.mkv', '.webm', '.m4v'];
	if (videoExtensions.includes(ext)) {
		return 'video';
	}

	// 音频类型
	const audioExtensions = ['.mp3', '.wav', '.aac', '.ogg', '.flac', '.wma', '.m4a'];
	if (audioExtensions.includes(ext)) {
		return 'audio';
	}

	// 文档类型
	const documentExtensions = ['.pdf', '.doc', '.docx', '.xls', '.xlsx', '.ppt', '.pptx', '.txt', '.rtf'];
	if (documentExtensions.includes(ext)) {
		return 'document';
	}

	// 默认返回document类型
	return 'document';
}

/**
 * 验证文件类型
 * @param {string} fileName 文件名
 * @param {string} fileType 文件类型
 * @returns {boolean} 是否有效
 */
const validateFileType = (fileName, fileType) => {
	// 文件类型配置
	const fileTypeConfig = {
		image: {
			extensions: ['.jpg', '.jpeg', '.png', '.gif', '.webp']
		},
		video: {
			extensions: ['.mp4', '.avi', '.mov', '.wmv']
		},
		document: {
			extensions: ['.pdf', '.doc', '.docx', '.xls', '.xlsx']
		},
		audio: {
			extensions: ['.mp3', '.wav', '.aac', '.ogg']
		},
		default: {
			extensions: ['.txt', '.log', '.dat']
		},
		backup: {
			extensions: ['.bak', '.backup', '.zip', '.tar.gz']
		},
		temp: {
			extensions: ['.tmp', '.temp']
		}
	};

	const config = fileTypeConfig[fileType];
	if (!config) return false;

	const ext = getFileExtension(fileName);
	return config.extensions.includes(ext);
}

/**
 * 生成文件路径
 * 文件名严格控制:
 * /uploads[固定值]
 * /image[类型：image|audio|video|document| 自定义类型手动上传使用不用考虑:default默认文件|backup备份/temp临时]
 * /user[模块类型:user|admin|system|other]
 * /20250505[年月日文件名]
 * /document_user_20250505_abcd1234567890_1715000000.pdf
 * /image_user_20250505_abcd1234567890_1715000000.jpg
 * /video_user_20250505_abcd1234567890_1715000000.mp4
 * /audio_user_20250505_abcd1234567890_1715000000.mp3
 * /other_user_20250505_abcd1234567890_1715000000.txt
 * /[文件名:类型_模块_年月日_随机字符串_时间戳.扩展名]
 *
 * @param {Object} options 选项对象
 * @param {string} options.fileName 文件名[路径+文件名]
 * @param {string} options.fileType 文件类型（可选，会根据文件名自动判断）
 * @param {string} options.moduleType 模块类型，默认'user'
 * @param {string} options.prefix 路径前缀，默认'uploads'
 * @param {boolean} options.useDatePath 是否使用日期路径，默认true
 * @param {boolean} options.useRandomString 是否使用随机字符串，默认true
 * @param {number} options.randomLength 随机字符串长度，默认12
 * @param {boolean} options.useTimestamp 是否使用时间戳，默认true
 * @param {string} options.fileNameFormat 文件名格式模板，默认'{fileType}_{moduleType}_{dateStr}_{random}_{timestamp}{extension}'
 * @param {string} options.pathFormat 路径格式模板，默认'{prefix}/{fileType}/{moduleType}/{dateStr}/{fileName}'
 * @param {string} options.separator 分隔符，默认'_'
 * @returns {Object|null} 文件路径信息，失败时返回null
 */
const generateFilePath = (options = {}) => {
	const {
		fileName,
		fileType,
		moduleType = 'user',
		prefix = 'uploads',
		useDatePath = true,
		useRandomString = true,
		randomLength = 12,
		useTimestamp = true,
		fileNameFormat = '{fileType}_{moduleType}_{dateStr}_{random}_{timestamp}{extension}',
		pathFormat = '{prefix}/{fileType}/{moduleType}/{dateStr}/{fileName}',
		separator = '_'
	} = options;

	// 首先获取文件类型 1.fileType > 2.fileName中获取的后缀 如果都没有则返回null
	let finalFileType = fileType;
	if (!finalFileType) {
		finalFileType = getFileExtension(fileName).replace('.', '');
	}
	if (!finalFileType) {
		return null;
	}

	// 验证文件类型
	if (!validateFileType(fileName, finalFileType)) {
		return null;
	}

	// 生成时间戳、随机字符串和日期
	const timestamp = useTimestamp ? Date.now() : '';
	const random = useRandomString ? stringRandom(randomLength, 1) : '';
	const dateStr = useDatePath ? getDateString() : '';

	// 获取文件扩展名
	const ext = getFileExtension(fileName);

	// 生成文件名
	let uniqueFileName = fileNameFormat
		.replace('{fileType}', finalFileType)
		.replace('{moduleType}', moduleType)
		.replace('{dateStr}', dateStr)
		.replace('{random}', random)
		.replace('{timestamp}', timestamp)
		.replace('{extension}', ext);

	// 清理多余的分隔符
	uniqueFileName = uniqueFileName.replace(new RegExp(`${separator}+`, 'g'), separator);
	uniqueFileName = uniqueFileName.replace(/^_+|_+$/g, ''); // 移除首尾的分隔符

	// 生成完整路径
	let fullPath = pathFormat
		.replace('{prefix}', prefix)
		.replace('{fileType}', finalFileType)
		.replace('{moduleType}', moduleType)
		.replace('{dateStr}', dateStr)
		.replace('{fileName}', uniqueFileName);

	// 清理路径中的多余斜杠
	fullPath = fullPath.replace(/\/+/g, '/').replace(/\/$/, '');
	return {
		uniqueFileName,// 唯一文件名
		fullPath,// 完整路径
		fileType: finalFileType,// 文件类型
		moduleType,// 模块类型
		extension: ext,// 文件扩展名
		timestamp,// 时间戳
		dateStr,// 日期字符串
		random,// 随机字符串
		originalName: fileName,// 原始文件名
		size: 0// 文件大小
	};
}

export {
	stringRandom,
	timeFormat,
	formatFileSize,
	formatNumber,
	formatPhone,
	formatCardNumber,
	formatIdCard,
	formatCurrency,
	formatPercent,
	convertColor,
	truncateString,
	camelToSnake,
	snakeToCamel,
	capitalize,
	titleCase,
	getFileExtension,
	getDateString,
	detectFileType,
	validateFileType,
	generateFilePath
};